#!/usr/bin/env python3
"""
HTML to PDF 转换服务
"""
import asyncio
import logging
import os
import sys
from datetime import datetime

import oss2
from dotenv import load_dotenv
from flask import Flask, request, jsonify
from flask_cors import CORS
from werkzeug.utils import secure_filename

from src.bid_analysis_service import BidAnalysisService
# 导入重构后的模块
from src.config import OSSConfig, CozeConfig, AppConfig
from src.exceptions import ConfigurationException
from src.html_pdf_service import HtmlToPdfService
from src.utils import OSSManager

# 加载环境变量
load_dotenv()

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stdout),
        logging.FileHandler('app.log', encoding='utf-8')
    ]
)
logger = logging.getLogger(__name__)

# 初始化配置
app_config = AppConfig()
oss_config = OSSConfig.from_env()
coze_config = CozeConfig.from_env()

app = Flask(__name__)
CORS(app)
app.config['MAX_CONTENT_LENGTH'] = app_config.max_content_length

# 初始化 OSS 客户端和管理器
if oss_config and oss_config.is_valid:
    auth = oss2.Auth(oss_config.access_key_id, oss_config.access_key_secret)
    bucket = oss2.Bucket(auth, oss_config.endpoint, oss_config.bucket_name)
    oss_manager = OSSManager(bucket)
    logger.info("OSS 客户端初始化成功")
else:
    oss_manager = None
    logger.warning("OSS 配置不完整，OSS 功能将不可用")

# 检查 Coze 配置
if coze_config and coze_config.is_valid:
    logger.info("Coze 配置验证成功")
else:
    logger.warning("Coze 配置不完整，投标分析功能将不可用")


def allowed_file(filename):
    """检查文件扩展名是否允许"""
    return '.' in filename and \
        filename.rsplit('.', 1)[1].lower() in app_config.allowed_extensions


# 初始化服务
def get_html_to_pdf_service():
    """获取 HTML 转 PDF 服务实例"""
    if not oss_manager:
        raise ConfigurationException("OSS 配置不完整，无法初始化服务")
    return HtmlToPdfService(oss_manager)


def get_bid_analysis_service():
    """获取投标分析服务实例"""
    if not coze_config or not coze_config.is_valid:
        raise ConfigurationException("Coze 配置不完整，无法初始化服务")
    return BidAnalysisService(coze_config)


@app.route('/api/convert', methods=['POST'])
def convert_html_to_pdf():
    """
    REST API 接口：将 OSS 上的 HTML 文件转换为 PDF 并上传回 OSS

    请求体 JSON 格式:
    {
        "html_url": "OSS 上的 HTML 文件 URL 或对象键"
    }

    返回 JSON 格式:
    {
        "success": true/false,
        "message": "处理结果信息",
        "pdf_url": "生成的 PDF 文件在 OSS 上的 URL",
        "pdf_object_key": "PDF 文件在 OSS 上的对象键"
    }
    """
    try:
        # 获取请求参数
        data = request.get_json()
        if not data or 'html_url' not in data:
            return jsonify({
                'success': False,
                'message': '请求参数错误，需要提供 html_url'
            }), 400

        html_url = data['html_url']

        # 异步处理转换任务
        async def process_conversion():
            html_file_path = None
            pdf_file_path = None
            html_to_pdf_service = get_html_to_pdf_service()

            try:
                # 1. 从 OSS 下载 HTML 文件
                html_file_path, original_object_key = await html_to_pdf_service.download_html_from_oss(html_url)

                # 2. 转换 HTML 为 PDF
                pdf_file_path = await html_to_pdf_service.convert_html_to_pdf(html_file_path)

                # 3. 上传 PDF 到 OSS
                pdf_url, pdf_object_key = await html_to_pdf_service.upload_pdf_to_oss(pdf_file_path, original_object_key)

                return {
                    'success': True,
                    'message': 'HTML 文件已成功转换为 PDF 并上传到 OSS',
                    'pdf_url': pdf_url,
                    'pdf_object_key': pdf_object_key
                }

            except Exception as e:
                return {
                    'success': False,
                    'message': f'转换失败: {str(e)}'
                }

            finally:
                # 清理临时文件
                html_to_pdf_service.cleanup_temp_files(html_file_path, pdf_file_path)

        # 运行异步任务
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        result = loop.run_until_complete(process_conversion())
        loop.close()

        status_code = 200 if result['success'] else 500
        return jsonify(result), status_code

    except Exception as e:
        return jsonify({
            'success': False,
            'message': f'服务器内部错误: {str(e)}'
        }), 500



@app.route('/api/health', methods=['GET'])
def health_check():
    """健康检查接口"""
    return jsonify({
        'status': 'healthy',
        'service': 'HTML to PDF Converter',
        'timestamp': datetime.now().isoformat()
    })


@app.route('/api/config', methods=['GET'])
def get_config():
    """获取配置信息（不包含敏感信息）"""
    return jsonify({
        'oss_endpoint': oss_config.endpoint if oss_config else None,
        'oss_bucket': oss_config.bucket_name if oss_config else None,
        'service_name': 'HTML to PDF Converter'
    })


@app.route('/api/bid-analysis/execute', methods=['POST'])
def execute_bid_analysis():
    """
    执行投标文件分析工作流

    请求体 JSON 格式:
    {
        "file_name": "96长春华翔车顶二层钢平台.PDF",
        "file_url": "https://autumn-coze-test.oss-cn-hangzhou.aliyuncs.com/project-bid-analysis/..."
    }

    返回 JSON 格式:
    {
        "debug_url": "https://www.coze.cn/work_flow?execute_id=7541722212181704730&space_id=7476012412643098633&workflow_id=7541634678315925539&execute_mode=2",
        "execute_id": "7541722212181704730",
        "message": "投标分析工作流已启动，请使用execute_id查询结果",
        "success": true
    }

    """
    try:
        # 获取请求参数
        data = request.get_json()
        if not data:
            return jsonify({
                'success': False,
                'message': '请求体不能为空'
            }), 400

        file_name = data.get('file_name')
        file_url = data.get('file_url')

        if not file_name or not file_url:
            return jsonify({
                'success': False,
                'message': '请求参数错误，需要提供 file_name 和 file_url'
            }), 400

        # 异步执行工作流
        async def process_workflow():
            try:
                service = get_bid_analysis_service()
                return await service.execute_workflow(file_name, file_url)
            except Exception as e:
                return {
                    'success': False,
                    'message': f'执行工作流失败: {str(e)}'
                }

        # 运行异步任务
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        result = loop.run_until_complete(process_workflow())
        loop.close()

        status_code = 200 if result['success'] else 500
        return jsonify(result), status_code

    except Exception as e:
        logger.error(f"执行投标分析失败: {str(e)}")
        return jsonify({
            'success': False,
            'message': f'服务器内部错误: {str(e)}'
        }), 500


@app.route('/api/bid-analysis/result/<execute_id>', methods=['GET'])
def get_bid_analysis_result(execute_id):
    """
    查询投标文件分析结果

    URL参数:
    - execute_id: 工作流执行ID

    返回 JSON 格式:
    {
        "create_time": 1755944038,
        "execute_id": "7541722212181704730",
        "execute_status": "Success",
        "result": {
        "content_type": 1,
        "data": "点击下载结果：https://autumn-coze-test.oss-cn-hangzhou.aliyuncs.com/project-bid-analysis%2FLR6ZNeZK_20250823_181431.pdf?OSSAccessKeyId=LTAI5tAoRFns6vD64z24WNq6&Expires=1758536071&Signature=fR%2FhBuQOOMvQDCdoEHTA1c0dqaw%3D",
        "type_for_model": 2
    },
        "success": true,
        "update_time": 1755944072,
        "usage": {
            "input_count": 1423,
            "output_count": 1243,
            "token_count": 2666
        }
    }

    """
    try:
        if not execute_id:
            return jsonify({
                'success': False,
                'message': '执行ID不能为空'
            }), 400

        # 异步查询结果
        async def query_result():
            try:
                service = get_bid_analysis_service()
                return await service.get_workflow_result(execute_id)
            except Exception as e:
                return {
                    'success': False,
                    'message': f'查询工作流结果失败: {str(e)}'
                }

        # 运行异步任务
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        result = loop.run_until_complete(query_result())
        loop.close()

        status_code = 200 if result['success'] else 500
        return jsonify(result), status_code

    except Exception as e:
        logger.error(f"查询投标分析结果失败: {str(e)}")
        return jsonify({
            'success': False,
            'message': f'服务器内部错误: {str(e)}'
        }), 500


@app.route('/api/file/upload', methods=['POST'])
def upload_file():
    """
    上传文件到OSS

    支持的文件类型: PDF, DOC, DOCX, TXT, XLS, XLSX

    请求参数:
    - file: 要上传的文件

    返回 JSON 格式:
    {
        "success": true/false,
        "file_url": "上传后的文件URL",
        "object_key": "文件在OSS中的对象键",
        "message": "处理结果信息"
    }
    """
    try:
        # 检查文件
        if 'file' not in request.files:
            return jsonify({
                'success': False,
                'message': '没有上传文件'
            }), 400

        file = request.files['file']
        if file.filename == '':
            return jsonify({
                'success': False,
                'message': '文件名不能为空'
            }), 400

        if not allowed_file(file.filename):
            return jsonify({
                'success': False,
                'message': f'不支持的文件类型，支持的类型: {", ".join(app_config.allowed_extensions)}'
            }), 400

        # 生成安全的文件名
        filename = secure_filename(file.filename)
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        object_key = f"uploads/{timestamp}_{filename}"

        # 上传到OSS
        try:
            file_content = file.read()
            bucket.put_object(object_key, file_content)

            file_url = oss_manager.generate_signed_url(object_key)
            logger.info(f"文件已上传到OSS: {object_key}")

            return jsonify({
                'success': True,
                'file_url': file_url,
                'file_name': filename,
                'object_key': object_key,
                'message': '文件上传成功'
            }), 200

        except Exception as e:
            logger.error(f"上传文件到OSS失败: {str(e)}")
            return jsonify({
                'success': False,
                'message': f'上传文件失败: {str(e)}'
            }), 500

    except Exception as e:
        logger.error(f"上传文件失败: {str(e)}")
        return jsonify({
            'success': False,
            'message': f'服务器内部错误: {str(e)}'
        }), 500


if __name__ == '__main__':
    # 检查必要的环境变量
    required_env_vars = ['OSS_ACCESS_KEY_ID', 'OSS_ACCESS_KEY_SECRET', 'OSS_ENDPOINT', 'OSS_BUCKET_NAME']
    missing_vars = [var for var in required_env_vars if not os.getenv(var)]

    if missing_vars:
        logger.error(f"缺少必要的环境变量: {', '.join(missing_vars)}")
        logger.error("请创建 .env 文件并配置这些变量")
        exit(1)

    # 从环境变量获取配置
    host = os.getenv('FLASK_HOST', '0.0.0.0')
    port = int(os.getenv('FLASK_PORT', 8080))
    debug = os.getenv('FLASK_DEBUG', 'False').lower() == 'true'

    logger.info("启动 HTML to PDF 转换服务...")
    logger.info(f"服务地址: http://{host}:{port}")

    if oss_config:
        logger.info(f"OSS 端点: {oss_config.endpoint}")
        logger.info(f"OSS 存储桶: {oss_config.bucket_name}")

    # 启动应用
    app.run(host=host, port=port, debug=debug)
